@@ -0,0 +1,29 @@  | 
            ||
| 1 | 
                +# EditorConfig is awesome: http://EditorConfig.org  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# top-most EditorConfig file  | 
            |
| 4 | 
                +root = true  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +# Unix-style newlines with a newline ending every file  | 
            |
| 7 | 
                +[*]  | 
            |
| 8 | 
                +end_of_line = lf  | 
            |
| 9 | 
                +insert_final_newline = false  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                +# 4 space indentation  | 
            |
| 12 | 
                +[*.py]  | 
            |
| 13 | 
                +indent_style = space  | 
            |
| 14 | 
                +indent_size = 4  | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                +# Tab indentation (no size specified)  | 
            |
| 17 | 
                +[*.js]  | 
            |
| 18 | 
                +indent_style = space  | 
            |
| 19 | 
                +indent_size = 4  | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                +# Tab indentation (no size specified)  | 
            |
| 22 | 
                +[*.html]  | 
            |
| 23 | 
                +indent_style = space  | 
            |
| 24 | 
                +indent_size = 4  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                +# Matches the exact files either package.json or .travis.yml  | 
            |
| 27 | 
                +[{package.json,.travis.yml}]
               | 
            |
| 28 | 
                +indent_style = space  | 
            |
| 29 | 
                +indent_size = 2  | 
            
                @@ -0,0 +1,63 @@  | 
            ||
| 1 | 
                +# Byte-compiled / optimized / DLL files  | 
            |
| 2 | 
                +__pycache__/  | 
            |
| 3 | 
                +*.py[cod]  | 
            |
| 4 | 
                +*.swp  | 
            |
| 5 | 
                +# C extensions  | 
            |
| 6 | 
                +*.so  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +# Distribution / packaging  | 
            |
| 9 | 
                +bin/  | 
            |
| 10 | 
                +build/  | 
            |
| 11 | 
                +develop-eggs/  | 
            |
| 12 | 
                +dist/  | 
            |
| 13 | 
                +eggs/  | 
            |
| 14 | 
                +lib/  | 
            |
| 15 | 
                +lib64/  | 
            |
| 16 | 
                +parts/  | 
            |
| 17 | 
                +sdist/  | 
            |
| 18 | 
                +venv/  | 
            |
| 19 | 
                +var/  | 
            |
| 20 | 
                +static/upload/  | 
            |
| 21 | 
                +*.egg-info/  | 
            |
| 22 | 
                +.installed.cfg  | 
            |
| 23 | 
                +*.egg  | 
            |
| 24 | 
                +*.sublime*  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                +# Installer logs  | 
            |
| 27 | 
                +pip-log.txt  | 
            |
| 28 | 
                +pip-delete-this-directory.txt  | 
            |
| 29 | 
                +  | 
            |
| 30 | 
                +# Unit test / coverage reports  | 
            |
| 31 | 
                +.tox/  | 
            |
| 32 | 
                +.coverage  | 
            |
| 33 | 
                +.cache  | 
            |
| 34 | 
                +nosetests.xml  | 
            |
| 35 | 
                +coverage.xml  | 
            |
| 36 | 
                +  | 
            |
| 37 | 
                +# Translations  | 
            |
| 38 | 
                +# *.mo  | 
            |
| 39 | 
                +  | 
            |
| 40 | 
                +# Mr Developer  | 
            |
| 41 | 
                +.mr.developer.cfg  | 
            |
| 42 | 
                +.project  | 
            |
| 43 | 
                +.pydevproject  | 
            |
| 44 | 
                +.settings  | 
            |
| 45 | 
                +# Rope  | 
            |
| 46 | 
                +.ropeproject  | 
            |
| 47 | 
                +  | 
            |
| 48 | 
                +# Django stuff:  | 
            |
| 49 | 
                +*.log  | 
            |
| 50 | 
                +*.pot  | 
            |
| 51 | 
                +  | 
            |
| 52 | 
                +# Sphinx documentation  | 
            |
| 53 | 
                +docs/_build/  | 
            |
| 54 | 
                +  | 
            |
| 55 | 
                +  | 
            |
| 56 | 
                +# Ignore For zhTimer  | 
            |
| 57 | 
                +.DS_Store  | 
            |
| 58 | 
                +db.sqlite3  | 
            |
| 59 | 
                +local_settings.py  | 
            |
| 60 | 
                +  | 
            |
| 61 | 
                +.idea/  | 
            |
| 62 | 
                +media/  | 
            |
| 63 | 
                +collect_static/  | 
            
                @@ -0,0 +1,14 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from django.contrib import admin  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +from account.models import LensmanInfo  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +class LensmanInfoAdmin(admin.ModelAdmin):  | 
            |
| 9 | 
                +    list_display = ('lensman_id', 'name', 'sex', 'phone', 'location', 'proportion', 'status', 'created_at', 'updated_at')
               | 
            |
| 10 | 
                +    search_fields = ('name', 'phone', 'location')
               | 
            |
| 11 | 
                +    list_filter = ('sex', 'status')
               | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                +admin.site.register(LensmanInfo, LensmanInfoAdmin)  | 
            
                @@ -0,0 +1,33 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +from __future__ import unicode_literals  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from django.db import models, migrations  | 
            |
| 5 | 
                +import shortuuidfield.fields  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +class Migration(migrations.Migration):  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                + dependencies = [  | 
            |
| 11 | 
                + ]  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                + operations = [  | 
            |
| 14 | 
                + migrations.CreateModel(  | 
            |
| 15 | 
                + name='LensmanInfo',  | 
            |
| 16 | 
                + fields=[  | 
            |
| 17 | 
                +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
               | 
            |
| 18 | 
                +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', verbose_name='status')),
               | 
            |
| 19 | 
                +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
               | 
            |
| 20 | 
                +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
               | 
            |
| 21 | 
                +                ('lensman_id', shortuuidfield.fields.ShortUUIDField(help_text='\u6444\u5f71\u5e08\u552f\u4e00\u6807\u8bc6', max_length=22, editable=False, db_index=True, blank=True)),
               | 
            |
| 22 | 
                +                ('name', models.CharField(help_text='\u6444\u5f71\u5e08\u59d3\u540d', max_length=255, null=True, verbose_name='name', blank=True)),
               | 
            |
| 23 | 
                +                ('sex', models.IntegerField(default=0, help_text='\u6444\u5f71\u5e08\u6027\u522b', verbose_name='sex', choices=[(0, '\u7537'), (1, '\u5973')])),
               | 
            |
| 24 | 
                +                ('phone', models.CharField(null=True, max_length=255, blank=True, help_text='\u6444\u5f71\u5e08\u7535\u8bdd', unique=True, verbose_name='phone', db_index=True)),
               | 
            |
| 25 | 
                +                ('location', models.CharField(help_text='\u6444\u5f71\u5e08\u5730\u5740', max_length=255, null=True, verbose_name='location', blank=True)),
               | 
            |
| 26 | 
                +                ('proportion', models.FloatField(default=1.0, help_text='\u6444\u5f71\u5e08\u5206\u6210\u6bd4\u4f8b\uff080.0 \uff5e 1.0\uff09', verbose_name='proportion')),
               | 
            |
| 27 | 
                + ],  | 
            |
| 28 | 
                +            options={
               | 
            |
| 29 | 
                + 'verbose_name': 'lensmaninfo',  | 
            |
| 30 | 
                + 'verbose_name_plural': 'lensmaninfo',  | 
            |
| 31 | 
                + },  | 
            |
| 32 | 
                + ),  | 
            |
| 33 | 
                + ]  | 
            
                @@ -0,0 +1,33 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from django.db import models  | 
            |
| 4 | 
                +from django.utils.translation import ugettext_lazy as _  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +from pai2.basemodels import CreateUpdateMixin  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +from shortuuidfield import ShortUUIDField  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                +class LensmanInfo(CreateUpdateMixin):  | 
            |
| 12 | 
                + MALE = 0  | 
            |
| 13 | 
                + FEMALE = 1  | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                + SEX_TYPE = (  | 
            |
| 16 | 
                + (MALE, u'男'),  | 
            |
| 17 | 
                + (FEMALE, u'女'),  | 
            |
| 18 | 
                + )  | 
            |
| 19 | 
                +  | 
            |
| 20 | 
                + lensman_id = ShortUUIDField(_(u'lensman_id'), max_length=255, help_text=u'摄影师唯一标识', db_index=True)  | 
            |
| 21 | 
                + name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'摄影师姓名')  | 
            |
| 22 | 
                + sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE, default=MALE, help_text=u'摄影师性别')  | 
            |
| 23 | 
                + phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'摄影师电话', db_index=True, unique=True)  | 
            |
| 24 | 
                + location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'摄影师地址')  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                + proportion = models.FloatField(_(u'proportion'), default=1.0, help_text=u'摄影师分成比例(0.0 ~ 1.0)')  | 
            |
| 27 | 
                +  | 
            |
| 28 | 
                + class Meta:  | 
            |
| 29 | 
                + verbose_name = _(u'lensmaninfo')  | 
            |
| 30 | 
                + verbose_name_plural = _(u'lensmaninfo')  | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                + def __unicode__(self):  | 
            |
| 33 | 
                + return unicode(self.pk)  | 
            
                @@ -0,0 +1,24 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from django.contrib.auth.models import User, Group  | 
            |
| 4 | 
                +from rest_framework import serializers  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +from account.models import LensmanInfo  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +class UserSerializer(serializers.HyperlinkedModelSerializer):  | 
            |
| 10 | 
                + class Meta:  | 
            |
| 11 | 
                + model = User  | 
            |
| 12 | 
                +        fields = ('url', 'username', 'email', 'groups')
               | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                +class GroupSerializer(serializers.HyperlinkedModelSerializer):  | 
            |
| 16 | 
                + class Meta:  | 
            |
| 17 | 
                + model = Group  | 
            |
| 18 | 
                +        fields = ('url', 'name')
               | 
            |
| 19 | 
                +  | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                +class LensmanInfoSerializer(serializers.HyperlinkedModelSerializer):  | 
            |
| 22 | 
                + class Meta:  | 
            |
| 23 | 
                + model = LensmanInfo  | 
            |
| 24 | 
                +        fields = ('lensman_id', 'name', 'sex', 'phone', 'location', 'proportion', 'created_at')
               | 
            
                @@ -0,0 +1,3 @@  | 
            ||
| 1 | 
                +from django.test import TestCase  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# Create your tests here.  | 
            
                @@ -0,0 +1,28 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from django.contrib.auth.models import User, Group  | 
            |
| 4 | 
                +from rest_framework import viewsets  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +from account.models import LensmanInfo  | 
            |
| 7 | 
                +from account.serializers import UserSerializer, GroupSerializer, LensmanInfoSerializer  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +class UserViewSet(viewsets.ModelViewSet):  | 
            |
| 11 | 
                + """  | 
            |
| 12 | 
                + API endpoint that allows users to be viewed or edited.  | 
            |
| 13 | 
                + """  | 
            |
| 14 | 
                +    queryset = User.objects.all().order_by('-date_joined')
               | 
            |
| 15 | 
                + serializer_class = UserSerializer  | 
            |
| 16 | 
                +  | 
            |
| 17 | 
                +  | 
            |
| 18 | 
                +class GroupViewSet(viewsets.ModelViewSet):  | 
            |
| 19 | 
                + """  | 
            |
| 20 | 
                + API endpoint that allows groups to be viewed or edited.  | 
            |
| 21 | 
                + """  | 
            |
| 22 | 
                + queryset = Group.objects.all()  | 
            |
| 23 | 
                + serializer_class = GroupSerializer  | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                +class LensmanInfoViewSet(viewsets.ModelViewSet):  | 
            |
| 27 | 
                +    queryset = LensmanInfo.objects.all().order_by('-created_at')
               | 
            |
| 28 | 
                + serializer_class = LensmanInfoSerializer  | 
            
                @@ -0,0 +1,3 @@  | 
            ||
| 1 | 
                +from django.contrib import admin  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# Register your models here.  | 
            
                @@ -0,0 +1,3 @@  | 
            ||
| 1 | 
                +from django.db import models  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# Create your models here.  | 
            
                @@ -0,0 +1,3 @@  | 
            ||
| 1 | 
                +from django.test import TestCase  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# Create your tests here.  | 
            
                @@ -0,0 +1,10 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from django.conf.urls import url  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +from photo import views as photo_views  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +urlpatterns = [  | 
            |
| 9 | 
                + url(r'^photos/upload$', photo_views.upload_photo, name='upload_photo'),  | 
            |
| 10 | 
                +]  | 
            
                @@ -0,0 +1,3 @@  | 
            ||
| 1 | 
                +from django.shortcuts import render  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# Create your views here.  | 
            
                @@ -0,0 +1,10 @@  | 
            ||
| 1 | 
                +#!/usr/bin/env python  | 
            |
| 2 | 
                +import os  | 
            |
| 3 | 
                +import sys  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +if __name__ == "__main__":  | 
            |
| 6 | 
                +    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pai2.settings")
               | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                + from django.core.management import execute_from_command_line  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                + execute_from_command_line(sys.argv)  | 
            
                @@ -0,0 +1,14 @@  | 
            ||
| 1 | 
                +#!/usr/bin/env python  | 
            |
| 2 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from django.db import models  | 
            |
| 5 | 
                +from django.utils.translation import ugettext_lazy as _  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +class CreateUpdateMixin(models.Model):  | 
            |
| 9 | 
                + status = models.BooleanField(_(u'status'), default=True, help_text=_(u'状态'))  | 
            |
| 10 | 
                + created_at = models.DateTimeField(_(u'created_at'), auto_now_add=True, editable=True, help_text=_(u'创建时间'))  | 
            |
| 11 | 
                + updated_at = models.DateTimeField(_(u'updated_at'), auto_now=True, editable=True, help_text=_(u'更新时间'))  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                + class Meta:  | 
            |
| 14 | 
                + abstract = True  | 
            
                @@ -0,0 +1,147 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +"""  | 
            |
| 4 | 
                +Django settings for pai2 project.  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +Generated by 'django-admin startproject' using Django 1.8.4.  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +For more information on this file, see  | 
            |
| 9 | 
                +https://docs.djangoproject.com/en/1.8/topics/settings/  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                +For the full list of settings and their values, see  | 
            |
| 12 | 
                +https://docs.djangoproject.com/en/1.8/ref/settings/  | 
            |
| 13 | 
                +"""  | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                +# Build paths inside the project like this: os.path.join(BASE_DIR, ...)  | 
            |
| 16 | 
                +import os  | 
            |
| 17 | 
                +  | 
            |
| 18 | 
                +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  | 
            |
| 19 | 
                +PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))  | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                +  | 
            |
| 22 | 
                +# Quick-start development settings - unsuitable for production  | 
            |
| 23 | 
                +# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/  | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                +# SECURITY WARNING: keep the secret key used in production secret!  | 
            |
| 26 | 
                +SECRET_KEY = 'aam6@6bh17d87bn-ax1@mcdrtbfm02y)_twd&!ewrr2^4581!c'  | 
            |
| 27 | 
                +  | 
            |
| 28 | 
                +# SECURITY WARNING: don't run with debug turned on in production!  | 
            |
| 29 | 
                +DEBUG = True  | 
            |
| 30 | 
                +  | 
            |
| 31 | 
                +ALLOWED_HOSTS = []  | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                +  | 
            |
| 34 | 
                +# Application definition  | 
            |
| 35 | 
                +  | 
            |
| 36 | 
                +INSTALLED_APPS = (  | 
            |
| 37 | 
                + 'django.contrib.admin',  | 
            |
| 38 | 
                + 'django.contrib.auth',  | 
            |
| 39 | 
                + 'django.contrib.contenttypes',  | 
            |
| 40 | 
                + 'django.contrib.sessions',  | 
            |
| 41 | 
                + 'django.contrib.messages',  | 
            |
| 42 | 
                + 'django.contrib.staticfiles',  | 
            |
| 43 | 
                + 'rest_framework',  | 
            |
| 44 | 
                + 'api',  | 
            |
| 45 | 
                + 'account',  | 
            |
| 46 | 
                + 'photo',  | 
            |
| 47 | 
                +)  | 
            |
| 48 | 
                +  | 
            |
| 49 | 
                +MIDDLEWARE_CLASSES = (  | 
            |
| 50 | 
                + 'django.contrib.sessions.middleware.SessionMiddleware',  | 
            |
| 51 | 
                + 'django.middleware.common.CommonMiddleware',  | 
            |
| 52 | 
                + # 'django.middleware.csrf.CsrfViewMiddleware',  | 
            |
| 53 | 
                + 'django.contrib.auth.middleware.AuthenticationMiddleware',  | 
            |
| 54 | 
                + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',  | 
            |
| 55 | 
                + 'django.contrib.messages.middleware.MessageMiddleware',  | 
            |
| 56 | 
                + 'django.middleware.clickjacking.XFrameOptionsMiddleware',  | 
            |
| 57 | 
                + 'django.middleware.security.SecurityMiddleware',  | 
            |
| 58 | 
                +)  | 
            |
| 59 | 
                +  | 
            |
| 60 | 
                +ROOT_URLCONF = 'pai2.urls'  | 
            |
| 61 | 
                +  | 
            |
| 62 | 
                +TEMPLATES = [  | 
            |
| 63 | 
                +    {
               | 
            |
| 64 | 
                + 'BACKEND': 'django.template.backends.django.DjangoTemplates',  | 
            |
| 65 | 
                + 'DIRS': [],  | 
            |
| 66 | 
                + 'APP_DIRS': True,  | 
            |
| 67 | 
                +        'OPTIONS': {
               | 
            |
| 68 | 
                + 'context_processors': [  | 
            |
| 69 | 
                + 'django.template.context_processors.debug',  | 
            |
| 70 | 
                + 'django.template.context_processors.request',  | 
            |
| 71 | 
                + 'django.contrib.auth.context_processors.auth',  | 
            |
| 72 | 
                + 'django.contrib.messages.context_processors.messages',  | 
            |
| 73 | 
                + ],  | 
            |
| 74 | 
                + },  | 
            |
| 75 | 
                + },  | 
            |
| 76 | 
                +]  | 
            |
| 77 | 
                +  | 
            |
| 78 | 
                +WSGI_APPLICATION = 'pai2.wsgi.application'  | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                +  | 
            |
| 81 | 
                +# Database  | 
            |
| 82 | 
                +# https://docs.djangoproject.com/en/1.8/ref/settings/#databases  | 
            |
| 83 | 
                +  | 
            |
| 84 | 
                +DATABASES = {
               | 
            |
| 85 | 
                +    'default': {
               | 
            |
| 86 | 
                + 'ENGINE': 'django.db.backends.mysql',  | 
            |
| 87 | 
                + 'NAME': 'pai2',  | 
            |
| 88 | 
                + 'USER': 'root',  | 
            |
| 89 | 
                + 'PASSWORD': '',  | 
            |
| 90 | 
                + }  | 
            |
| 91 | 
                +}  | 
            |
| 92 | 
                +  | 
            |
| 93 | 
                +  | 
            |
| 94 | 
                +# Internationalization  | 
            |
| 95 | 
                +# https://docs.djangoproject.com/en/1.8/topics/i18n/  | 
            |
| 96 | 
                +  | 
            |
| 97 | 
                +LANGUAGE_CODE = 'zh_CN'  | 
            |
| 98 | 
                +  | 
            |
| 99 | 
                +TIME_ZONE = 'Asia/Shanghai'  | 
            |
| 100 | 
                +  | 
            |
| 101 | 
                +USE_I18N = True  | 
            |
| 102 | 
                +  | 
            |
| 103 | 
                +USE_L10N = True  | 
            |
| 104 | 
                +  | 
            |
| 105 | 
                +USE_TZ = True  | 
            |
| 106 | 
                +  | 
            |
| 107 | 
                +  | 
            |
| 108 | 
                +# Static files (CSS, JavaScript, Images)  | 
            |
| 109 | 
                +# https://docs.djangoproject.com/en/1.8/howto/static-files/  | 
            |
| 110 | 
                +  | 
            |
| 111 | 
                +STATICFILES_DIRS = (  | 
            |
| 112 | 
                +    os.path.join(PROJ_DIR, 'static').replace('\\', '/'),
               | 
            |
| 113 | 
                +)  | 
            |
| 114 | 
                +  | 
            |
| 115 | 
                +STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static').replace('\\', '/')
               | 
            |
| 116 | 
                +  | 
            |
| 117 | 
                +STATIC_URL = '/static/'  | 
            |
| 118 | 
                +  | 
            |
| 119 | 
                +STATICFILES_FINDERS = (  | 
            |
| 120 | 
                + 'django.contrib.staticfiles.finders.FileSystemFinder',  | 
            |
| 121 | 
                + 'django.contrib.staticfiles.finders.AppDirectoriesFinder',  | 
            |
| 122 | 
                + # 'django.contrib.staticfiles.finders.DefaultStorageFinder',  | 
            |
| 123 | 
                +)  | 
            |
| 124 | 
                +  | 
            |
| 125 | 
                +MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/')
               | 
            |
| 126 | 
                +  | 
            |
| 127 | 
                +MEDIA_URL = '/media/'  | 
            |
| 128 | 
                +  | 
            |
| 129 | 
                +# REST_FRAMEWORK 设置  | 
            |
| 130 | 
                +# See http://www.django-rest-framework.org/#example  | 
            |
| 131 | 
                +REST_FRAMEWORK = {
               | 
            |
| 132 | 
                + # Use Django's standard `django.contrib.auth` permissions,  | 
            |
| 133 | 
                + # or allow read-only access for unauthenticated users.  | 
            |
| 134 | 
                + # 'DEFAULT_PERMISSION_CLASSES': [  | 
            |
| 135 | 
                + # 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',  | 
            |
| 136 | 
                + # ]  | 
            |
| 137 | 
                +    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',),
               | 
            |
| 138 | 
                + 'PAGE_SIZE': 1  | 
            |
| 139 | 
                +}  | 
            |
| 140 | 
                +  | 
            |
| 141 | 
                +# 域名设置  | 
            |
| 142 | 
                +DOMAIN = 'http://xfoto.com.cn'  | 
            |
| 143 | 
                +  | 
            |
| 144 | 
                +try:  | 
            |
| 145 | 
                + from local_settings import *  | 
            |
| 146 | 
                +except ImportError:  | 
            |
| 147 | 
                + pass  | 
            
                @@ -0,0 +1,48 @@  | 
            ||
| 1 | 
                +"""pai2 URL Configuration  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +The `urlpatterns` list routes URLs to views. For more information please see:  | 
            |
| 4 | 
                + https://docs.djangoproject.com/en/1.8/topics/http/urls/  | 
            |
| 5 | 
                +Examples:  | 
            |
| 6 | 
                +Function views  | 
            |
| 7 | 
                + 1. Add an import: from my_app import views  | 
            |
| 8 | 
                + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')  | 
            |
| 9 | 
                +Class-based views  | 
            |
| 10 | 
                + 1. Add an import: from other_app.views import Home  | 
            |
| 11 | 
                + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')  | 
            |
| 12 | 
                +Including another URLconf  | 
            |
| 13 | 
                + 1. Add an import: from blog import urls as blog_urls  | 
            |
| 14 | 
                + 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))  | 
            |
| 15 | 
                +"""  | 
            |
| 16 | 
                +from django.conf import settings  | 
            |
| 17 | 
                +from django.conf.urls import include, url  | 
            |
| 18 | 
                +from django.conf.urls.static import static  | 
            |
| 19 | 
                +from django.contrib import admin  | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                +from rest_framework import routers  | 
            |
| 22 | 
                +from account import views as account_views  | 
            |
| 23 | 
                +from photo import views as photo_views  | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                +router = routers.DefaultRouter()  | 
            |
| 26 | 
                +# router.register(r'users', account_views.UserViewSet)  | 
            |
| 27 | 
                +# router.register(r'groups', account_views.GroupViewSet)  | 
            |
| 28 | 
                +router.register(r'lensmans', account_views.LensmanInfoViewSet)  | 
            |
| 29 | 
                +router.register(r'photos', photo_views.PhotoInfoViewSet)  | 
            |
| 30 | 
                +  | 
            |
| 31 | 
                +urlpatterns = [  | 
            |
| 32 | 
                + url(r'^pai2admin/', include(admin.site.urls)),  | 
            |
| 33 | 
                +]  | 
            |
| 34 | 
                +  | 
            |
| 35 | 
                +urlpatterns += [  | 
            |
| 36 | 
                +    url(r'^api/', include('api.urls', namespace='api')),
               | 
            |
| 37 | 
                +    # url(r'^photo/', include('photo.urls', namespace='photo'))
               | 
            |
| 38 | 
                +]  | 
            |
| 39 | 
                +  | 
            |
| 40 | 
                +# Wire up our API using automatic URL routing.  | 
            |
| 41 | 
                +# Additionally, we include login URLs for the browsable API.  | 
            |
| 42 | 
                +urlpatterns += [  | 
            |
| 43 | 
                + url(r'^api/', include(router.urls)),  | 
            |
| 44 | 
                +    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
               | 
            |
| 45 | 
                +]  | 
            |
| 46 | 
                +  | 
            |
| 47 | 
                +urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)  | 
            |
| 48 | 
                +urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)  | 
            
                @@ -0,0 +1,22 @@  | 
            ||
| 1 | 
                +# morefun_uwsgi.ini file  | 
            |
| 2 | 
                +[uwsgi]  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +# Django-related settings  | 
            |
| 5 | 
                +# the base directory (full path)  | 
            |
| 6 | 
                +chdir = /home/paiai/work/pai2  | 
            |
| 7 | 
                +# Django's wsgi file  | 
            |
| 8 | 
                +module = pai2.wsgi  | 
            |
| 9 | 
                +# the virtualenv (full path)  | 
            |
| 10 | 
                +# home = /path/to/virtualenv  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +# process-related settings  | 
            |
| 13 | 
                +# master  | 
            |
| 14 | 
                +master = true  | 
            |
| 15 | 
                +# maximum number of worker processes  | 
            |
| 16 | 
                +processes = 10  | 
            |
| 17 | 
                +# the socket (use the full path to be safe  | 
            |
| 18 | 
                +socket = /home/paiai/work/pai2/pai2/uwsgi/pai2.sock  | 
            |
| 19 | 
                +# ... with appropriate permissions - may be needed  | 
            |
| 20 | 
                +chmod-socket = 777  | 
            |
| 21 | 
                +# clear environment on exit  | 
            |
| 22 | 
                +vacuum = true  | 
            
                @@ -0,0 +1,35 @@  | 
            ||
| 1 | 
                +# pai2_nginx.conf  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# the upstream component nginx needs to connect to  | 
            |
| 4 | 
                +upstream pai2 {
               | 
            |
| 5 | 
                + # server unix:///home/paiai/work/pai2/pai2/uwsgi/pai2.sock; # for a file socket  | 
            |
| 6 | 
                + server 127.0.0.1:8888; # for a web port socket (we'll use this first)  | 
            |
| 7 | 
                +}  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +# configuration of the server  | 
            |
| 10 | 
                +server {
               | 
            |
| 11 | 
                + # the port your site will be served on  | 
            |
| 12 | 
                + listen 80;  | 
            |
| 13 | 
                + # the domain name it will serve for  | 
            |
| 14 | 
                + server_name .xfoto.com.cn; # substitute your machine's IP address or FQDN  | 
            |
| 15 | 
                + charset utf-8;  | 
            |
| 16 | 
                +  | 
            |
| 17 | 
                + # max upload size  | 
            |
| 18 | 
                + client_max_body_size 75M; # adjust to taste  | 
            |
| 19 | 
                +  | 
            |
| 20 | 
                + # Django media  | 
            |
| 21 | 
                +    location /media  {
               | 
            |
| 22 | 
                + alias /home/paiai/work/pai2/media; # your Django project's media files - amend as required  | 
            |
| 23 | 
                + }  | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                +    location /static {
               | 
            |
| 26 | 
                + alias /home/paiai/work/pai2/collect_static; # your Django project's static files - amend as required  | 
            |
| 27 | 
                + }  | 
            |
| 28 | 
                +  | 
            |
| 29 | 
                + # Finally, send all non-media requests to the Django server.  | 
            |
| 30 | 
                +    location / {
               | 
            |
| 31 | 
                + # uwsgi_pass pai2;  | 
            |
| 32 | 
                + proxy_pass http://pai2;  | 
            |
| 33 | 
                + include /home/paiai/work/pai2/pai2/uwsgi/uwsgi_params; # the uwsgi_params file you installed  | 
            |
| 34 | 
                + }  | 
            |
| 35 | 
                +}  | 
            
                @@ -0,0 +1,2 @@  | 
            ||
| 1 | 
                +killall -9 uwsgi  | 
            |
| 2 | 
                +echo "2敏加油~~~!!!↖(^ω^)↗"  | 
            
                @@ -0,0 +1,2 @@  | 
            ||
| 1 | 
                +nohup uwsgi --ini pai2.ini &>pai2.log &  | 
            |
| 2 | 
                +echo "Start Success !!!"  | 
            
                @@ -0,0 +1,15 @@  | 
            ||
| 1 | 
                +uwsgi_param QUERY_STRING $query_string;  | 
            |
| 2 | 
                +uwsgi_param REQUEST_METHOD $request_method;  | 
            |
| 3 | 
                +uwsgi_param CONTENT_TYPE $content_type;  | 
            |
| 4 | 
                +uwsgi_param CONTENT_LENGTH $content_length;  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +uwsgi_param REQUEST_URI $request_uri;  | 
            |
| 7 | 
                +uwsgi_param PATH_INFO $document_uri;  | 
            |
| 8 | 
                +uwsgi_param DOCUMENT_ROOT $document_root;  | 
            |
| 9 | 
                +uwsgi_param SERVER_PROTOCOL $server_protocol;  | 
            |
| 10 | 
                +uwsgi_param UWSGI_SCHEME $scheme;  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +uwsgi_param REMOTE_ADDR $remote_addr;  | 
            |
| 13 | 
                +uwsgi_param REMOTE_PORT $remote_port;  | 
            |
| 14 | 
                +uwsgi_param SERVER_PORT $server_port;  | 
            |
| 15 | 
                +uwsgi_param SERVER_NAME $server_name;  | 
            
                @@ -0,0 +1,3 @@  | 
            ||
| 1 | 
                +from django.shortcuts import render  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# Create your views here.  | 
            
                @@ -0,0 +1,16 @@  | 
            ||
| 1 | 
                +"""  | 
            |
| 2 | 
                +WSGI config for pai2 project.  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +It exposes the WSGI callable as a module-level variable named ``application``.  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +For more information on this file, see  | 
            |
| 7 | 
                +https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/  | 
            |
| 8 | 
                +"""  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +import os  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +from django.core.wsgi import get_wsgi_application  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pai2.settings")
               | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                +application = get_wsgi_application()  | 
            
                @@ -0,0 +1,9 @@  | 
            ||
| 1 | 
                +#!/bin/bash  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# Ignoring autogenerated files  | 
            |
| 4 | 
                +# -- Migration directories  | 
            |
| 5 | 
                +# Ignoring error codes  | 
            |
| 6 | 
                +# -- E128 continuation line under-indented for visual indent  | 
            |
| 7 | 
                +# -- E501 line too long  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +pep8 --exclude=migrations --ignore=E128,E501 .  | 
            
                @@ -0,0 +1,13 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from django.contrib import admin  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +from photo.models import PhotosInfo  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +class PhotosInfoAdmin(admin.ModelAdmin):  | 
            |
| 9 | 
                +    list_display = ('lensman_id', 'session_id', 'photo_id', 'photo_path', 'status', 'created_at', 'updated_at')
               | 
            |
| 10 | 
                +    list_filter = ('lensman_id', 'status')
               | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                +admin.site.register(PhotosInfo, PhotosInfoAdmin)  | 
            
                @@ -0,0 +1,34 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +from __future__ import unicode_literals  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from django.db import models, migrations  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +class Migration(migrations.Migration):  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                + dependencies = [  | 
            |
| 10 | 
                + ]  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                + operations = [  | 
            |
| 13 | 
                + migrations.CreateModel(  | 
            |
| 14 | 
                + name='PhotosInfo',  | 
            |
| 15 | 
                + fields=[  | 
            |
| 16 | 
                +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
               | 
            |
| 17 | 
                +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', verbose_name='status')),
               | 
            |
| 18 | 
                +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
               | 
            |
| 19 | 
                +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
               | 
            |
| 20 | 
                +                ('lesman_id', models.CharField(max_length=255, blank=True, help_text='\u6444\u5f71\u5e08\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='lesman_id', db_index=True)),
               | 
            |
| 21 | 
                +                ('session_id', models.CharField(max_length=255, blank=True, help_text='\u7167\u7247\u7ec4\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='session_id', db_index=True)),
               | 
            |
| 22 | 
                +                ('photo_id', models.CharField(null=True, max_length=255, blank=True, help_text='\u7167\u7247\u552f\u4e00\u6807\u8bc6', unique=True, verbose_name='photo_id', db_index=True)),
               | 
            |
| 23 | 
                +                ('photo_path', models.CharField(help_text='\u7167\u7247\u5b58\u653e\u8def\u5f84', max_length=255, null=True, verbose_name='photo_path', blank=True)),
               | 
            |
| 24 | 
                + ],  | 
            |
| 25 | 
                +            options={
               | 
            |
| 26 | 
                + 'verbose_name': 'photosinfo',  | 
            |
| 27 | 
                + 'verbose_name_plural': 'photosinfo',  | 
            |
| 28 | 
                + },  | 
            |
| 29 | 
                + ),  | 
            |
| 30 | 
                + migrations.AlterIndexTogether(  | 
            |
| 31 | 
                + name='photosinfo',  | 
            |
| 32 | 
                +            index_together=set([('lesman_id', 'session_id')]),
               | 
            |
| 33 | 
                + ),  | 
            |
| 34 | 
                + ]  | 
            
                @@ -0,0 +1,27 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +from __future__ import unicode_literals  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from django.db import models, migrations  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +class Migration(migrations.Migration):  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                + dependencies = [  | 
            |
| 10 | 
                +        ('photo', '0001_initial'),
               | 
            |
| 11 | 
                + ]  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                + operations = [  | 
            |
| 14 | 
                + migrations.AddField(  | 
            |
| 15 | 
                + model_name='photosinfo',  | 
            |
| 16 | 
                + name='lensman_id',  | 
            |
| 17 | 
                + field=models.CharField(max_length=255, blank=True, help_text='\u6444\u5f71\u5e08\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='lensman_id', db_index=True),  | 
            |
| 18 | 
                + ),  | 
            |
| 19 | 
                + migrations.AlterIndexTogether(  | 
            |
| 20 | 
                + name='photosinfo',  | 
            |
| 21 | 
                +            index_together=set([('lensman_id', 'session_id')]),
               | 
            |
| 22 | 
                + ),  | 
            |
| 23 | 
                + migrations.RemoveField(  | 
            |
| 24 | 
                + model_name='photosinfo',  | 
            |
| 25 | 
                + name='lesman_id',  | 
            |
| 26 | 
                + ),  | 
            |
| 27 | 
                + ]  | 
            
                @@ -0,0 +1,39 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from django.conf import settings  | 
            |
| 4 | 
                +from django.db import models  | 
            |
| 5 | 
                +from django.utils.translation import ugettext_lazy as _  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +from pai2.basemodels import CreateUpdateMixin  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +class PhotosInfo(CreateUpdateMixin):  | 
            |
| 11 | 
                + lensman_id = models.CharField(_(u'lensman_id'), max_length=255, blank=True, null=True, help_text=u'摄影师唯一标识', db_index=True)  | 
            |
| 12 | 
                + session_id = models.CharField(_(u'session_id'), max_length=255, blank=True, null=True, help_text=u'照片组唯一标识', db_index=True)  | 
            |
| 13 | 
                + photo_id = models.CharField(_(u'photo_id'), max_length=255, blank=True, null=True, help_text=u'照片唯一标识', db_index=True, unique=True)  | 
            |
| 14 | 
                + photo_path = models.CharField(_(u'photo_path'), max_length=255, blank=True, null=True, help_text=u'照片存放路径')  | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                + class Meta:  | 
            |
| 17 | 
                +        verbose_name = _('photosinfo')
               | 
            |
| 18 | 
                +        verbose_name_plural = _('photosinfo')
               | 
            |
| 19 | 
                + index_together = [  | 
            |
| 20 | 
                + ['lensman_id', 'session_id'],  | 
            |
| 21 | 
                + ]  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                + def __unicode__(self):  | 
            |
| 24 | 
                +        return u'{0.pk}'.format(self)
               | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                + @property  | 
            |
| 27 | 
                + def photo_url(self):  | 
            |
| 28 | 
                +        return u'{0}/media/{1}'.format(settings.DOMAIN, self.photo_path) if self.photo_path else ''
               | 
            |
| 29 | 
                +  | 
            |
| 30 | 
                + def _data(self):  | 
            |
| 31 | 
                +        return {
               | 
            |
| 32 | 
                + 'pk': self.pk,  | 
            |
| 33 | 
                + 'lensman_id': self.lensman_id,  | 
            |
| 34 | 
                + 'session_id': self.session_id,  | 
            |
| 35 | 
                + 'photo_id': self.photo_id,  | 
            |
| 36 | 
                + 'photo_url': self.photo_url,  | 
            |
| 37 | 
                + }  | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                + data = property(_data)  | 
            
                @@ -0,0 +1,10 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from photo.models import PhotosInfo  | 
            |
| 4 | 
                +from rest_framework import serializers  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +class PhotosInfoSerializer(serializers.HyperlinkedModelSerializer):  | 
            |
| 8 | 
                + class Meta:  | 
            |
| 9 | 
                + model = PhotosInfo  | 
            |
| 10 | 
                +        fields = ('lensman_id', 'session_id', 'photo_id', 'photo_path', 'created_at')
               | 
            
                @@ -0,0 +1,3 @@  | 
            ||
| 1 | 
                +from django.test import TestCase  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +# Create your tests here.  | 
            
                @@ -0,0 +1,71 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from django.core.files.storage import default_storage  | 
            |
| 4 | 
                +from django.http import JsonResponse  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +from rest_framework import viewsets  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +from account.models import LensmanInfo  | 
            |
| 9 | 
                +from photo.models import PhotosInfo  | 
            |
| 10 | 
                +from photo.serializers import PhotosInfoSerializer  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +import os  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                +# [How to do a PUT request with curl?](http://stackoverflow.com/questions/13782198/how-to-do-a-put-request-with-curl)  | 
            |
| 16 | 
                +# Unfortunately, the -T is no substitute for -X PUT if you want to specify parameters with -d or -F.  | 
            |
| 17 | 
                +# -T sends the content of a file via PUT. To achieve the GET after a redirect, add the parameter --location  | 
            |
| 18 | 
                +#  | 
            |
| 19 | 
                +# -F, --form <name=content>  | 
            |
| 20 | 
                +# (HTTP) This lets curl emulate a filled-in form in which a user has pressed the submit button. This causes curl to POST data  | 
            |
| 21 | 
                +# using the Content-Type multipart/form-data according to RFC 2388. This enables uploading of binary files etc. To force the  | 
            |
| 22 | 
                +# 'content' part to be a file, prefix the file name with an @ sign. To just get the content part from a file, prefix the file  | 
            |
| 23 | 
                +# name with the symbol <. The difference between @ and < is then that @ makes a file get attached in the post as a file upload,  | 
            |
| 24 | 
                +# while the < makes a text field and just get the contents for that text field from a file.  | 
            |
| 25 | 
                +#  | 
            |
| 26 | 
                +# curl -X POST -F lensman_id=123 -F session_id=456 -F photo_id=789 -F photo=@7056288a9ddf2db294cf50a943920989.jpg;filename=789 http://xfoto.com.cn/api/photos/upload  | 
            |
| 27 | 
                +def upload_photo(request):  | 
            |
| 28 | 
                +    lensman_id = request.POST.get('lensman_id', '')
               | 
            |
| 29 | 
                +    session_id = request.POST.get('session_id', '')
               | 
            |
| 30 | 
                +    photo_id = request.POST.get('photo_id', '')
               | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                +    photo = request.FILES.get('photo', '')
               | 
            |
| 33 | 
                +  | 
            |
| 34 | 
                + if not (lensman_id and session_id and photo_id and photo):  | 
            |
| 35 | 
                +        return JsonResponse({
               | 
            |
| 36 | 
                + 'status': 400,  | 
            |
| 37 | 
                + 'message': u'参数错误',  | 
            |
| 38 | 
                + })  | 
            |
| 39 | 
                +  | 
            |
| 40 | 
                + try:  | 
            |
| 41 | 
                + LensmanInfo.objects.get(lensman_id=lensman_id)  | 
            |
| 42 | 
                + except LensmanInfo.DoesNotExist:  | 
            |
| 43 | 
                +        return JsonResponse({
               | 
            |
| 44 | 
                + 'status': 400,  | 
            |
| 45 | 
                + 'message': u'参数错误',  | 
            |
| 46 | 
                + })  | 
            |
| 47 | 
                +  | 
            |
| 48 | 
                + _, extension = os.path.splitext(photo.name)  | 
            |
| 49 | 
                +    photo_path = 'photo/{0}/{1}/{2}{3}'.format(lensman_id, session_id, photo_id, extension)
               | 
            |
| 50 | 
                +  | 
            |
| 51 | 
                + if default_storage.exists(photo_path):  | 
            |
| 52 | 
                + default_storage.delete(photo_path)  | 
            |
| 53 | 
                + default_storage.save(photo_path, photo)  | 
            |
| 54 | 
                +  | 
            |
| 55 | 
                + photo, created = PhotosInfo.objects.get_or_create(  | 
            |
| 56 | 
                + lensman_id=lensman_id,  | 
            |
| 57 | 
                + session_id=session_id,  | 
            |
| 58 | 
                + photo_id=photo_id,  | 
            |
| 59 | 
                + photo_path=photo_path  | 
            |
| 60 | 
                + )  | 
            |
| 61 | 
                +  | 
            |
| 62 | 
                +    return JsonResponse({
               | 
            |
| 63 | 
                + 'status': 200,  | 
            |
| 64 | 
                + 'message': u'照片上传成功',  | 
            |
| 65 | 
                + 'data': photo.data,  | 
            |
| 66 | 
                + })  | 
            |
| 67 | 
                +  | 
            |
| 68 | 
                +  | 
            |
| 69 | 
                +class PhotoInfoViewSet(viewsets.ModelViewSet):  | 
            |
| 70 | 
                +    queryset = PhotosInfo.objects.all().order_by('-created_at')
               | 
            |
| 71 | 
                + serializer_class = PhotosInfoSerializer  | 
            
                @@ -0,0 +1,12 @@  | 
            ||
| 1 | 
                +CodeConvert==2.0.3  | 
            |
| 2 | 
                +Django==1.8.4  | 
            |
| 3 | 
                +MySQL-python==1.2.5  | 
            |
| 4 | 
                +TimeConvert==1.0.7  | 
            |
| 5 | 
                +django-shortuuidfield==0.1.3  | 
            |
| 6 | 
                +djangorestframework==3.3.1  | 
            |
| 7 | 
                +ipdb==0.8.1  | 
            |
| 8 | 
                +ipython==4.0.0  | 
            |
| 9 | 
                +pep8==1.6.2  | 
            |
| 10 | 
                +pillow==2.9.0  | 
            |
| 11 | 
                +pytz==2015.7  | 
            |
| 12 | 
                +uWSGI==2.0.11.1  |